
#if defined(WIN32) || defined(WIN64)
#pragma unmanaged
#endif

#include <Liberty3D/Engine/Coroutine.h>

#include <exception>

using namespace Liberty::Engine;

CoroutineEntry::CoroutineEntry(CoroutineType t, const std::shared_ptr<Object>& o, const std::string& n) :
    _object(o),
    _name  (n),
    _type  (t),
    _status(READY)
{
}

bool CoroutineEntry::ready(const Performance::Counter& currentTime) const {
    switch (_status) {
    default:
    case READY:
    case WAIT_FOR_END_OF_FRAME:
    case WAIT_FOR_FIXED_UPDATE:
        return true;

    case WAIT_FOR_OPERATION:
        return _operation->isDone();

    case WAIT_FOR_SECONDS:
        return (_until >= currentTime);

    case DONE:
        return false;
    }
}

bool CoroutineEntry::tick(const Performance::Counter& currentTime) {
    if (ready(currentTime)) {
        _status = READY;

        boost::any o = _coroutine->tick();

        if (o.empty()) {
            return true;
        }

        try {
            std::shared_ptr<IOperation>* op = boost::any_cast<std::shared_ptr<IOperation> >(&o);

            if (op) {
                _status    = WAIT_FOR_OPERATION;
                _operation = *op;
                return true;
            }
        }
        catch (boost::bad_any_cast) {
        }

        try {
            WaitForSeconds* wsec = boost::any_cast<WaitForSeconds>(&o);

            if (wsec) {
                _status = WAIT_FOR_SECONDS;
                _until  = currentTime + wsec->delay();
                return true;
            }
        }
        catch (boost::bad_any_cast) {
        }

        try {
            WaitForEndOfFrame* wsec = boost::any_cast<WaitForEndOfFrame>(&o);

            if (wsec) {
                _status = WAIT_FOR_END_OF_FRAME;
                return true;
            }
        }
        catch (boost::bad_any_cast) {
        }

        try {
            WaitForFixedUpdate* wsec = boost::any_cast<WaitForFixedUpdate>(&o);

            if (wsec) {
                _status = WAIT_FOR_FIXED_UPDATE;
                return true;
            }
        }
        catch (boost::bad_any_cast) {
        }

        try {
            EndOfCoroutine* eoc = boost::any_cast<EndOfCoroutine>(&o);

            if (eoc) {
                _status = DONE;
                return false;
            }
        }
        catch (boost::bad_any_cast) {
        }

        throw std::runtime_error("Unknown return value for Coroutine::tick");
    }

    return true;
}
